import 'dart:convert';
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:mybaseplus/base/abstract/IFFR.dart';
import 'package:mybaseplus/base/tool/api/IAppEnv.dart';
import 'package:mybaseplus/base/tool/empty/FFEmpty.dart';
import 'package:mybaseplus/base/tool/globalMethod/FFSafeValue.dart';
import 'package:mybaseplus/base/tool/pprint/FFLog.dart';
import 'package:mybaseplus/base/tool/entitylog/MyLog.dart';

/**
 * 打包命令
    #    flutter build appbundle --obfuscate --split-debug-info=/Users/os/Desktop/obfuscate_appbundle --no-sound-null-safety
    #    flutter build apk --obfuscate --split-debug-info=/Users/os/Desktop/obfuscate --no-sound-null-safety
 */

/**
 * 提交前的注意事项
 * 1。kToolbarHeight = 44
 * 2 setState方法首行添加 if (this.mounted != true) {return;}
 */

class ApiUtils {
  ///这些默认值，不要改动
  static String GetMethod = 'get';
  static String PostMethd = 'post';
  static String OkCode = "1";
  static const String PAGELIMIT = "100";
  static const int receiveTimeout = 45000; // 秒
  static IAppEnv appApi = AppBaseEnv();

  ///获取当前api前缀
  static Future<String> BASEURL() async {
    if (appApi.isProduct) {
      return appApi.env_product;
    }

    return appApi.env_local;
  }

  static String defaultMsg() {
    return "error";
  }

  /**
   * @description: 初始化dio
   * @param {*}
   * @return {*}
   */
  static Future<Dio> initDio({
    Map<String, dynamic>? headers,
    Map<String, dynamic>? extra,
    bool isUseBaseUrl = true,
    int connectTimeout = receiveTimeout,
  }) async {
    headers = appApi.setHeader(headers);
    BaseOptions baseOptions = FFEmpty.mapIsEmpty(headers)
        ? BaseOptions(
            connectTimeout: connectTimeout, receiveTimeout: connectTimeout, extra: extra)
        : BaseOptions(
            headers: headers,
            connectTimeout: connectTimeout,
            receiveTimeout: connectTimeout,
            extra: extra);

    // 是否使用host
    if (isUseBaseUrl) {
      baseOptions.baseUrl = await BASEURL();
    }
    Dio dio = Dio(baseOptions);

    // 添加缓存拦截器
    // dio.interceptors.add(NetCacheInterceptor());

    // 解决证书验证问题，验证强制返回true：
    (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
      client.badCertificateCallback = (cert, host, port) {
        return true;
      };
    };
    return dio;
  }

  /**
   * @description: 发送网络请求
   * @param method 请求方式; path 请求的地址; param 请求参数; isFormData 是否表单数据;
   *        headers 请求头; isUseBaseUrl 是否使用host;
   * @return {*}
   */
  static Future<IFFR<T>> methodAwait<T>(
    String method,
    String url, {
    Map<String, dynamic>? param,
    List? listParam,
    Map<String, dynamic>? extra,
    Map<String, dynamic>? headers,
    bool isUseBaseUrl = true,
    bool isShowLog = false,
    bool isFormData = false, //上传用
    int connectTimeout = receiveTimeout,
    Function(int progress, int total)? progress,
    bool? verifyUserState = true,
  }) async {
    DateTime startDate = DateTime.now();
    Dio? dio;
    Map<String, dynamic>? result;

    var response = null;
    if (param == null) param = Map(); // 处理参数为空的情况
    if (FFEmpty.mapIsEmpty(headers)) headers = {};

    dio = await initDio(
        headers: headers,
        isUseBaseUrl: isUseBaseUrl,
        extra: extra,
        connectTimeout: connectTimeout);
    R<T> apiR = R(msg: ApiUtils.defaultMsg());

    var data;
    Headers? responseHeader;

    if (method == GetMethod) {
      try {
        response = await dio.get(url, queryParameters: param);
      } catch (e) {
        printError(url, method, e, param, headers);
        apiR.rStatus = RStatus.error;
        return apiR;
      }
    } else if (method == PostMethd) {
      dynamic tempParam = param;
      if (isFormData) {
        tempParam = FormData.fromMap(param);
      }

      if (!FFEmpty.listIsEmpty(listParam)) {
        tempParam = listParam;
      }

      try {
        response =
            await dio.post(url, data: tempParam, onSendProgress: (int p, int total) {
          if (progress != null) progress(p, total);
        });
      } catch (e) {
        printError(url, method, e, param, headers);
        apiR.rStatus = RStatus.error;
        return apiR;
      }
    }
    data = response.data;
    responseHeader = response.headers;

    if (responseHeader != null) {
      apiR.responseHeader = responseHeader.map;
    }

    if (data == null) {
      //超时
      apiR.rStatus = RStatus.timeout;
      return apiR;
    }

    try {
      if (data is String) {
        result = json.decode(data);
      } else {
        result = data as Map<String, dynamic>;
      }
    } catch (e) {
      //解析出错
      apiR.rStatus = RStatus.error;
      return apiR;
    }

    apiR.originalData = result; //原始数据
    if (isShowLog == true || appApi.printApiData == true) {
      DateTime endDate = DateTime.now();
      Duration difference = endDate.difference(startDate);
      int milliseconds = difference.inMilliseconds;
      FFLog.success("接口打印信息");
      Mylog.p(
          url: url.startsWith("http") ? url : "${await BASEURL()}$url",
          param: param,
          header: headers,
          // responseHeader: responseHeader?.map,
          result: data,
          apiTime: "$milliseconds 毫秒");
    }
    return apiR;
  }

  static printError(String url, String method, dynamic e, Map<String, dynamic>? param,
      Map<String, dynamic>? headers) {
    if (appApi.printApiData == true) {
      if (e is DioError) {
        DioError dioError = e as DioError;
        FFLog.error(
            "ApiUtils ${method} 请求出错  \n $url apiError  \n ${dioError.message}\n param : ${param.toString()} \n header : ${headers.toString()}");
      } else {
        FFLog.error(
            "ApiUtils ${method} 请求出错  \n $url apiError  \n $e\n param : ${param.toString()} \n header : ${headers.toString()}");
      }
    } else {
      FFLog.error(
          "ApiUtils ${method} 请求出错  \n $url apiError  \n param : ${param.toString()} \n header : ${headers.toString()}");
    }
  }

  //请求完接口后，立即执行该方法
  static handleIFFRProperties(
    IFFR r, {
    Function(dynamic responseData)? parse,
    Function(dynamic originalData)? needParseData, //data可能会包很多层
    bool? paging = false,
    String? limit = PAGELIMIT,
    bool? noData = false, //接口的data本身就没有值为true
  }) {
    if (r.rStatus == RStatus.error) {
      return;
    }

    if (r.originalData == null) {
      r.rStatus = RStatus.noData;
      return;
    }

    if (r.originalData is Map) {
      if (FFEmpty.mapIsEmpty(r.originalData)) {
        r.rStatus = RStatus.noData;
        return;
      }

      Map dataMap = r.originalData as Map;
      r.code = globalSafeValueFromMap<String>(dataMap, "code") ?? "-1";
      r.msg = globalSafeValueFromMap<String>(dataMap, "msg") ?? "";
      r.time = globalSafeValueFromMap<String>(dataMap, "time") ?? "0";

      dynamic t;
      if (needParseData != null) {
        t = needParseData(globalSafeValueFromMap(dataMap, "data"));
      } else {
        t = globalSafeValueFromMap(dataMap, "data");
      }

      if (t != null) {
        if (t is Map && FFEmpty.mapIsEmpty(t)) {
          r.rStatus = RStatus.noData;
          r.data = null;
          return;
        } else if (t is List && FFEmpty.listIsEmpty(t)) {
          r.rStatus = RStatus.noData;
          r.data = null;
          return;
        }

        //解析
        if (parse != null && t != null) {
          r.data = parse(t);
        }
        r.rStatus = RStatus.result;
      } else {
        r.rStatus = RStatus.noData;

        if (noData == true) {
          if (r.code == OkCode) {
            r.rStatus = RStatus.result;
          }
        }
      }

      if (paging == true) {
        //todo:根据数据看是否有分页
        if (r.data is List) {
          List pageList = r.data as List;
          r.haveNext = (pageList.length >= int.parse(limit ?? PAGELIMIT));
        } else {
          r.haveNext = false;
        }
      } else {
        r.haveNext = false;
      }
    }
  }

  ///如果IFFR data 是list,则执行此方法
  static List<T> handleIFFRList<T>(dynamic datas,
      {required Function(dynamic item) parseList}) {
    List<T> list = [];

    if (FFEmpty.listIsEmpty(datas)) {
      return list;
    }

    List forList = datas as List;
    for (int i = 0; i < forList.length; i++) {
      list.add(parseList(forList[i]));
    }

    return list;
  }

  ///如果data字段下，还有lists字段，或者其他字段
  static dynamic needParseData_plist(dynamic orig, String pname) {
    if (orig is Map) {
      Map origMap = orig as Map;
      return globalSafeValueFromMap(origMap, pname);
    }
    return null;
  }
}
